#!/usr/bin/env python3

import apiclient
from apiclient.error_handlers import BaseErrorHandler
from apiclient.response import Response
from apiclient import exceptions
import json


class MyErrorHandler(BaseErrorHandler):

    @staticmethod
    def get_exception(response: Response) -> exceptions.APIRequestError:
        """Parses client errors to extract bad request reasons."""
        if 400 <= response.get_status_code() < 500:
            data = response.get_raw_data()
            return exceptions.ClientError(data)

        return exceptions.APIRequestError("something went wrong")


class GiteeAPIClient(apiclient.APIClient):
    def __init__(self, name, token):
        super().__init__(authentication_method=apiclient.QueryParameterAuthentication('access_token', token),
                         response_handler=apiclient.JsonResponseHandler,
                         request_formatter=apiclient.JsonRequestFormatter,
                         error_handler=MyErrorHandler
                         )
        self.name = name

    def current_user(self):
        url = 'https://gitee.com/api/v5/user'
        return self.get(url)['login']

    def create_e_repo(self,
                      name,
                      description='',
                      homepage='',
                      has_issues=True,
                      has_wiki=True,
                      can_comment=True,
                      auto_init=False,
                      gitignore_template=None,
                      license_template=None,
                      path='',
                      private=0,
                      outsourced=False,
                      project_creator='',
                      members=[]):
        # 创建企业仓库
        url = f'https://gitee.com/api/v5/enterprises/{self.name}/repos'
        data = dict(
            name=name,
            description=description,
            homepage=homepage,
            has_issues=has_issues,
            has_wiki=has_wiki,
            can_comment=can_comment,
            auto_init=auto_init,
            gitignore_template=gitignore_template,
            license_template=license_template,
            path=path,
            private=private,
            outsourced=outsourced,
            project_creator=project_creator,
            members=','.join(members))
        return self.post(url, data)

    def get_repo_collaborator(self, repo):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/collaborators'
        page = 0
        all_users = []
        while 1:
            page += 1
            users = self.get(url, params={'page':page, 'per_page':100})
            all_users.extend(users)
            if len(users) < 100:
                break
        return all_users

    def add_repo_collaborator(self, repo, username, permission='push'):
        # 添加仓库协作者
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/collaborators/{username}'
        return self.post(url, {'permission': permission})

    def del_repo_collaborator(self, repo, username):
        # 删除仓库协作者
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/collaborators/{username}'
        return self.delete(url)

    def del_repo(self, repo):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}'
        return self.delete(url)

    def clear_repo(self, repo):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}'
        return self.put(repo)

    def protect_repo_branch(self, repo, branch):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/branches/{branch}/protection'
        return self.put(url)

    def unprotect_repo_branch(self, repo, branch):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/branches/{branch}/protection'
        return self.delete(url)

    def merge_pr(self, repo, number,
                 merge_method='merge',
                 prune_source_branch='False',
                 title='',
                 description=''):
        # 合并PR
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/pulls/{number}/merge'
        data = dict(merge_method=merge_method,
                    prune_source_branch=prune_source_branch,
                    title=title,
                    description=description)
        return self.put(url, data)

    def update_pr(self, repo, number,
                  title='',
                  body='',
                  state=None,
                  milestone_number=None,
                  labels: list=[],
                  assignees_number=None,
                  testers_number=None):
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/pulls/{number}'

        data = dict(title=title,
                    body=body
                    )
        if state:
            data['state'] = state
        if milestone_number is not None:
            data['milestone_number'] = milestone_number
        if labels:
            data['labels'] = ','.join(labels)
        if assignees_number is not None:
            data['assignees_number'] = assignees_number
        if testers_number is not None:
            data['testers_number'] = testers_number

        return self.patch(url, data)

    def close_pr(self, repo, number):
        return self.update_pr(repo, number, state='closed')

    def add_pr_labels(self, repo, number, labels: list):
        # 给PR添加标签
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/pulls/{number}/labels'
        return self.post(url, {'body': labels})

    def del_pr_labels(self, repo, number, labels: list):
        name = ','.join(labels)
        url = f'https://gitee.com/api/v5/repos/{self.name}/{repo}/pulls/{number}/labels/{name}'
        return self.delete(url)
